#include "ZGLWidget.h"
#include "maininterface.h"
#include "mainwindow.h"
#include "renderer/environment.h"

using namespace PBVP;

ZGLWidget::ZGLWidget(MainInterface *pMainInterface, MainWindow* parent) 
: QGLWidget(parent), m_Env(pMainInterface->getEnvironment())
{
	m_pMainInterface = pMainInterface;
	rotMtx.identity();
	//transMtx.identity();
	transMtx = TranslateMatrix44(0, 0, -4); 
	m_Translation.makeTrans(0, 0, -4);

	fov = 60;
	m_near = 0.1f;
	m_far = 30.0f;
	rotFactor = 0.05f;
	transFactor = 0.05f;
	m_FullScreen = false;
	m_pParent = parent;
	m_ShowBBox = true;
	setMinimumWidth(300);
	setMinimumHeight(200);
}

ZGLWidget::~ZGLWidget(void)
{
}

void ZGLWidget::initializeGL()
{  
	GLenum err = glewInit();
	if (GLEW_OK != err)
	{
		// Problem: glewInit failed, something is seriously wrong. 
		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
		// should not continue
		exit(1);
	}

	m_pMainInterface->getEnvironment().apply();
}

void ZGLWidget::resizeGL(int w, int h)
{
	GLfloat r = (float) w / (float) h;

	glViewport( 0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(fov, r, m_near, m_far);
	glMatrixMode(GL_MODELVIEW);

}

void ZGLWidget::paintGL()
{
	float matrix[16];
	Matrix4 transform;
	Matrix4 mtx;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glPushMatrix();

	//transMtx.toArray(matrix);
	//glMultMatrixf(matrix);
	////
	//rotMtx.toArray(matrix);
	//glMultMatrixf(matrix);

	transform = m_Translation * Matrix4(m_Rotation);
	transform.toOGLArray(matrix);
	// m_Env.viewingTransform().toOGLArray(matrix);
	glLoadMatrixf(matrix);

	//show a bounding box
	if(m_ShowBBox) {
		glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
		glDisable(GL_LIGHTING);
		//glColor3f(1, 1, 1);
		glutWireCube(2);
		glPopAttrib();
	}
	// scale and translate data into the canonical box
	AxisAlignedBox bbox = m_pMainInterface->getDataManager()->boundingBox();
	Vector3 center = bbox.getCenter();
	float scaleFactor = 2.0f / bbox.getLongEdge();
	
	mtx.setScale(Vector3(scaleFactor, scaleFactor, scaleFactor));
	mtx = mtx * Matrix4::translateMatrix(-center);
	transform = transform* mtx;
	transform.toOGLArray(matrix);
	glLoadMatrixf(matrix);
	m_Env.setViewingTransform(transform);
	
	// glScalef(scaleFactor, scaleFactor, scaleFactor);
	// glTranslatef(-center.x, -center.y, -center.z);
	m_pMainInterface->getDataManager()->render();
	
	glPopMatrix();
}

void ZGLWidget::keyPressEvent(QKeyEvent *e)
{
	switch (e->key()) {
	case Qt::Key_R:

		break;
	case Qt::Key_F:
		if(e->nativeModifiers() && Qt::ControlModifier) { // CTRL-F pressed
			viewFullScreen();
		}
		break;
	case Qt::Key_Escape:
		endFullScreen();
		break;
	default:
		break;
	}
}

void ZGLWidget::mousePressEvent(QMouseEvent *e)
{
	button = e->button();
	mouseXY[0] = e->x();
	mouseXY[1] = e->y();
}

void ZGLWidget::mouseMoveEvent(QMouseEvent *e)
{
	matrix44 mtx; 
	Matrix4 matrix4;
	Quaternion rot;

	int x = e->x();
	int y = e->y();
	int px = mouseXY[0];
	int py = mouseXY[1];

	switch (button) {
	case Qt::LeftButton:			// rotate with the left mouse button
		mtx = RotateRadMatrix44('x', rotFactor*(y-py));
		rotMtx = mtx * rotMtx;
		mtx = RotateRadMatrix44('y', rotFactor*(x-px));
		rotMtx = mtx * rotMtx;
		rot = Quaternion(rotFactor*(y-py), Vector3(1, 0, 0)) * Quaternion(rotFactor*(x-px), Vector3(0, 1, 0));
		m_Rotation = rot * m_Rotation;
		break;
	case Qt::MidButton:			 // translate with the middle mouse button
		mtx = TranslateMatrix44(transFactor*(x-px), -transFactor*(y-py), 0.0f);
		transMtx *= mtx;
		matrix4.makeTrans(transFactor*(x-px), -transFactor*(y-py), 0.0f);
		m_Translation = m_Translation * matrix4;
		break;
	case Qt::RightButton:		 // zoom with right mouse button 
		mtx = TranslateMatrix44(0.0f, 0.0f, transFactor*(y-py));
		transMtx *= mtx;
		matrix4.makeTrans(0.0f, 0.0f, transFactor*(y-py));
		m_Translation = m_Translation* matrix4;
		break;
	default:                          
		break;
	}
	mouseXY[0] = x;
	mouseXY[1] = y;
	updateGL();
}  

void ZGLWidget::viewFullScreen()
{
	if(m_FullScreen) return;
	m_FullScreen = true;
	
	setParent(NULL);
	move(QPoint(0, 0));
	show();
	showFullScreen();
}

void ZGLWidget::endFullScreen()
{
	if(!m_FullScreen) return;
	m_FullScreen = false;
	showNormal();
	setParent(m_pParent);
	m_pParent->setCentralWidget(this);
	show();
}

//////////////////////////////////////////////////////////////////////////
// Public slots
//////////////////////////////////////////////////////////////////////////
void ZGLWidget::showBBox(bool visible)
{
	m_ShowBBox = visible;
}